package com.iup.tp.twitup.core;

import java.io.File;
import java.util.Properties;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.UIManager;

import com.iup.tp.twitup.common.Constants;
import com.iup.tp.twitup.common.PropertiesManager;
import com.iup.tp.twitup.datamodel.Database;
import com.iup.tp.twitup.datamodel.IDatabase;
import com.iup.tp.twitup.events.file.IWatchableDirectory;
import com.iup.tp.twitup.events.file.WatchableDirectory;
import com.iup.tp.twitup.ihm.ConsoleIHM;
import com.iup.tp.twitup.ihm.TwitupMainView;
import com.iup.tp.twitup.ihm.TwitupMock;

/**
 * Classe principale l'application.
 * 
 * @author S.Lucas
 */
public class Twitup
{
  /**
   * Base de données.
   */
  protected IDatabase mDatabase;

  /**
   * Gestionnaire des entités contenu de la base de données.
   */
  protected EntityManager mEntityManager;

  /**
   * Vue principale de l'application.
   */
  protected TwitupMainView mMainView;

  /**
   * Classe de surveillance de répertoire
   */
  protected IWatchableDirectory mWatchableDirectory;

  /**
   * Répertoire d'échange de l'application.
   */
  protected String mExchangeDirectoryPath;

  /**
   * Idnique si le mode bouchoné est activé.
   */
  protected boolean mIsMockEnabled = true;

  /**
   * Nom de la classe de l'UI. (celle de l'OS par défaut)
   */
  protected String mUiClassName = UIManager.getSystemLookAndFeelClassName();

  /**
   * Constructeur.
   */
  public Twitup()
  {
    // Chargement des configurations de l'application
    this.loadProperties();

    // Init du look and feel de l'application
    this.initLookAndFeel();

    // Initialisation de la base de données
    this.initDatabase();

    // Initialisation du bouchon de travail
    this.initMock();

    // Initialisation de l'IHM
    this.initGui();

    // Initialisation du répertoire d'échange
    this.initDirectory();

    // Sauvegarde des propriétés
    this.writeProperties();

    try
    {
      Thread.sleep(100000);
    }
    catch (InterruptedException e)
    {}
  }

  /**
   * Chargement des configurations de l'application
   */
  protected void loadProperties()
  {
    // Chargement du fichier de configuration
    Properties properties = PropertiesManager.loadProperties(Constants.CONFIGURATION_FILE);

    // Chargement du répertoire d'échange
    String directoryPath = properties.getProperty(Constants.CONFIGURATION_KEY_EXCHANGE_DIRECTORY, "");
    if (directoryPath.isEmpty() == false)
    {
      mExchangeDirectoryPath = directoryPath;
    }

    // Chargement de la configuration de l'UI
    String uiClassName = properties.getProperty(Constants.CONFIGURATION_KEY_UI_CLASS_NAME, "");
    if (uiClassName.isEmpty() == false)
    {
      mUiClassName = uiClassName;
    }

    // Chargement du mode bouchoné
    mIsMockEnabled = Boolean.valueOf(properties.getProperty(Constants.CONFIGURATION_KEY_MOCK_ENABLED,
                                                            Boolean.toString(mIsMockEnabled)));
  }

  /**
   * Sauvegarde du fichier de configuration de l'application
   */
  protected void writeProperties()
  {
    // Création des propriétés
    Properties properties = new Properties();
    properties.setProperty(Constants.CONFIGURATION_KEY_EXCHANGE_DIRECTORY, mExchangeDirectoryPath);
    properties.setProperty(Constants.CONFIGURATION_KEY_UI_CLASS_NAME, mUiClassName);
    properties.setProperty(Constants.CONFIGURATION_KEY_MOCK_ENABLED, Boolean.toString(mIsMockEnabled));

    // Ecriture du fichier de configuration
    PropertiesManager.writeProperties(properties, Constants.CONFIGURATION_FILE);
  }

  /**
   * Initialisation du look and feel de l'application.
   */
  protected void initLookAndFeel()
  {
    try
    {
      UIManager.setLookAndFeel(mUiClassName);
    }
    catch (Throwable t)
    {
      System.err.println("Impossible d'assigner le look and feel : '" + mUiClassName + "'");
      t.printStackTrace();
    }
  }

  /**
   * Initialisation de l'interface graphique.
   */
  protected void initGui()
  {
    // Affichage console des notifications
    ConsoleIHM consoleIHM = new ConsoleIHM();
    mDatabase.addObserver(consoleIHM);

    mMainView = new TwitupMainView();
    mMainView.showGUI();
  }

  /**
   * Initialisation du répertoire d'échange (depuis la conf ou depuis un file chooser).
   */
  protected void initDirectory()
  {
    File exchangeDirectory = null;

    if (mExchangeDirectoryPath != null)
    {
      exchangeDirectory = new File(mExchangeDirectoryPath);
    }

    // Si le répertoire n'a pas pu être chargé depuis les configuration
    if (this.isValideExchangeDirectory(exchangeDirectory) == false)
    {
      // Configuration du sélecteur de dossier
      JFileChooser fileChooser = new JFileChooser();
      fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
      fileChooser.setDialogTitle("Choisir le répertoire d'échange");
      fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

      // Récupération du résultat
      JFrame mainFrame = null;
      if (this.mMainView != null)
      {
        mainFrame = this.mMainView.getMainFrame();
      }
      fileChooser.showOpenDialog(mainFrame);
      exchangeDirectory = fileChooser.getSelectedFile();
    }

    // Si le répertoire est valide
    if (this.isValideExchangeDirectory(exchangeDirectory))
    {
      // Initialisation de la surveillance
      this.initDirectory(exchangeDirectory.getAbsolutePath());
    }
    else
    {
      this.initDirectory();
    }
  }

  /**
   * Indique si le fichier donné est valide pour servire de répertoire d'échange
   * 
   * @param directory
   *          , Répertoire à tester.
   */
  protected boolean isValideExchangeDirectory(File directory)
  {
    // Valide si répertoire disponible en lecture et écriture
    return directory != null && directory.exists() && directory.isDirectory() && directory.canRead()
        && directory.canWrite();
  }

  /**
   * Initialisation du mode bouchoné de l'application
   */
  protected void initMock()
  {
    TwitupMock mock = new TwitupMock(this.mDatabase, this.mEntityManager);
    mock.showGUI();
  }

  /**
   * Initialisation de la base de données
   */
  protected void initDatabase()
  {
    mDatabase = new Database();
    mEntityManager = new EntityManager(mDatabase);
  }

  /**
   * Initialisation du répertoire d'échange.
   * 
   * @param directoryPath
   */
  public void initDirectory(String directoryPath)
  {
    mExchangeDirectoryPath = directoryPath;
    mWatchableDirectory = new WatchableDirectory(directoryPath);
    mEntityManager.setExchangeDirectory(directoryPath);

    mWatchableDirectory.initWatching();
    mWatchableDirectory.addObserver(mEntityManager);
  }

  public void setDirectoryPath(String directoryPath)
  {
    mWatchableDirectory.changeDirectory(directoryPath);
    mWatchableDirectory.initWatching();
    mEntityManager.setExchangeDirectory(directoryPath);
  }

}
